﻿// Simbolos.cs created with MonoDevelop
// User: renato at 23:31 19/5/2008
//
// To change standard headers go to Edit->Preferences->Coding->Standard Headers
//

using System;
using System.Collections;

namespace compilador
{
	public enum TipoToken{
		t_nenhum,
		t_ponto,
		t_igual,
		t_pontoevirgula,
		t_abrepar,
		t_fechapar,
		t_virgula,
		t_doispontosigual,
		t_doispontos,
		t_maiorigual,
		t_maior,
		t_menorigual,
		t_menor,
		t_diferente,
		t_soma,
		t_subtracao,
		t_multiplicacao,
		t_divisao,
		t_identificador,
		t_program,
		t_var,
		t_begin,
		t_numreal,
		t_numint,
		t_end,
		t_tipodado,
		t_procedure,
		t_else,
		t_read,
		t_write,
		t_while,
		t_if,
		t_then,
		t_do
	} 
	
	public struct ItemSimbolo
	{
		public TipoToken Token;
		public String Lexema;		
	}

    public struct ItemSimboloTS
    {
        public TipoToken Token;
        public String Lexema;
        public int PosMemoria;
        public TipoToken Tipo;
        public ItemSimboloTS(TipoToken aToken, String aLexema, int aPosMemoria, TipoToken aTipo)
        {
            Token = aToken;
            Lexema = aLexema;
            PosMemoria = aPosMemoria;
            Tipo = aTipo;
        }
    }
	
	public class Simbolos
	{
		Hashtable lista;
        public int Escopo;
        public bool AdicionaTokens = true;
        public bool isProcedure = false;
        public bool isDecProcedure = false;
        public bool isDecNomePrograma = false;
        int posMemoria = -1;
        int posMemoriaProcedure = -1;
        public bool AssignMem = false;

        public void RestauraProcedure()
        {
            posMemoriaProcedure = posMemoria+1;
        }

        public int getNextPosMemoria(Boolean aIncrementa, Boolean aProcedure)
        {
            if (!AssignMem)
                return -1;
            if (aIncrementa)
            {
                if (!aProcedure)
                    return ++posMemoria;
                else
                    return ++posMemoriaProcedure;
            }
            else
            {
                if (!aProcedure)
                    return posMemoria + 1;
                else
                    return posMemoriaProcedure + 1;
            }
        }

		public Simbolos()
		{
			lista = new Hashtable();
			
		}

        public void Insere(TipoToken pToken, String pLexema)
        {
            ItemSimboloTS tmp;
            int lEscopo = Escopo;
            if (isProcedure && !isDecProcedure)
                lEscopo = 0;

            tmp.Token = pToken;
            tmp.Lexema = pLexema;
            tmp.PosMemoria = -1;
            if (!isDecNomePrograma && pToken.Equals(TipoToken.t_identificador) && (!isProcedure || isDecProcedure))
              tmp.PosMemoria = getNextPosMemoria(true,!Escopo.Equals(0));
            tmp.Tipo = TipoToken.t_nenhum;
            lista.Add(Convert.ToString(lEscopo) + pLexema, tmp);
        }
		
		public ItemSimboloTS Localiza(String pLexema)
		{

			ItemSimboloTS tmp;
            ItemSimbolo tmp2;
            bool EscopoRaiz = false;
            bool ExisteID = false;

            if (isProcedure && lista.ContainsKey(Convert.ToString(0) + pLexema) && !AdicionaTokens)
            {
                Console.WriteLine("Procedure redeclarada: {0}", pLexema);
                Singleton.Instancia.deuErro = true;
                //return new ItemSimboloTS(TipoToken.t_identificador, pLexema, -1, TipoToken.t_nenhum);
                Environment.Exit(1);
            }

            if ((lista.ContainsKey(Convert.ToString(Escopo) + pLexema)))
            {
                ExisteID = true;
                EscopoRaiz  = false;
            }
            if (lista.ContainsKey(Convert.ToString(0) + pLexema))
            {
                ExisteID = true;
                EscopoRaiz = true;
            }
            
            if (AdicionaTokens && ExisteID)
            {
                ItemSimboloTS it;
                if ((EscopoRaiz && Escopo == 0) || (!EscopoRaiz && Escopo !=0))
                {
                    if (EscopoRaiz)
                        it = (ItemSimboloTS)lista[Convert.ToString(0) + pLexema];
                    else
                        it = (ItemSimboloTS)lista[Convert.ToString(Escopo) + pLexema];
                    if ((it.Token.Equals(TipoToken.t_identificador)))
                    {
                        Console.WriteLine("Variável redeclarada: {0}", pLexema);
                        Environment.Exit(1);
                    }
                }
            }
            if (isProcedure)
            {
                ExisteID = lista.ContainsKey(Convert.ToString(Escopo) + pLexema);
                if (lista.ContainsKey(Convert.ToString(0) + pLexema))
                {
                    ItemSimboloTS simb = (ItemSimboloTS)lista[Convert.ToString(0) + pLexema];
                    ExisteID = simb.Token != TipoToken.t_identificador;
                }
            }

			//Console.WriteLine("lexema ->"+pLexema);
			if (!ExisteID)
            {
                if (!AdicionaTokens)
                {
                    Console.WriteLine("Identificador não declarado: {0}", pLexema);
                    Environment.Exit(1);
                    /*ImprimeLista();
                    Singleton.Instancia.deuErro = true;
                    return new ItemSimboloTS(TipoToken.t_identificador, pLexema, -1, TipoToken.t_nenhum);*/
                }
				tmp.Lexema = pLexema;
				tmp.Token = TipoToken.t_identificador;
                tmp.PosMemoria = -1;
                tmp.Tipo = TipoToken.t_nenhum;
				Insere(tmp.Token, pLexema);
				//Console.WriteLine("ID inserido na tabela de símbolos");
			}else
                if (lista.ContainsKey(Convert.ToString(Escopo)+pLexema))
				  tmp = (ItemSimboloTS)lista[Convert.ToString(Escopo)+pLexema];
                else
                  tmp = (ItemSimboloTS)lista[Convert.ToString(0)+pLexema];

            tmp2.Lexema = tmp.Lexema;
            tmp2.Token = tmp.Token;
			return tmp; 
		}

        public int ObtemPosMem(String aLexema)
        {
            if (lista.ContainsKey(Convert.ToString(Escopo) + aLexema))
            {
                ItemSimboloTS s = (ItemSimboloTS)lista[Convert.ToString(Escopo) + aLexema];
                return s.PosMemoria;
            }

            if (lista.ContainsKey(Convert.ToString(0) + aLexema))
            {
                ItemSimboloTS s = (ItemSimboloTS)lista[Convert.ToString(0) + aLexema];
                return s.PosMemoria;
            }
            return -1;
        }

        public void AlteraPosMem(String aLexema,int aPosMem)
        {
            if (lista.ContainsKey(Convert.ToString(0)+aLexema))
            {
                string Chave = Convert.ToString(0)+aLexema;
                ItemSimboloTS s = (ItemSimboloTS)lista[Chave];
                s.PosMemoria = aPosMem;
                lista.Remove(Chave);
                lista.Add(Chave, s);
                return;
            }
            
            if (lista.ContainsKey(Convert.ToString(Escopo) + aLexema))
            {
                string Chave = Convert.ToString(Escopo) + aLexema;
                ItemSimboloTS s = (ItemSimboloTS)lista[Chave];
                s.PosMemoria = aPosMem;
                lista.Remove(Chave);
                lista.Add(Chave, s);
                return;
            }
        }

        public void AlteraTipo(String aLexema, TipoToken aTipo)
        {
            string Chave = "";
            if (lista.ContainsKey(Convert.ToString(0) + aLexema))
            {
                Chave = Convert.ToString(0) + aLexema;
            }

            if (lista.ContainsKey(Convert.ToString(Escopo) + aLexema))
            {
                Chave = Convert.ToString(Escopo) + aLexema;
            }
            if (!Chave.Equals(""))
            {
                ItemSimboloTS s = (ItemSimboloTS)lista[Chave];
                s.Tipo = aTipo;
                lista.Remove(Chave);
                lista.Add(Chave, s);
            }
        }

        public bool ExisteLexema(string aLexema, int aEscopo)
        {
            if (lista.ContainsKey(Convert.ToString(aEscopo) + aLexema))
                return true;
            return false;
        }

		public void ImprimeLista()
		{
			Console.WriteLine("Lista de Lexemas");
            Console.WriteLine(String.Format("{0,-10} | {1,-20} | {2,-10} | {3,-10}", "Lexema","Token","Pos. Mem","Tipo"));
            foreach(ItemSimboloTS tmp in lista.Values){
                Console.WriteLine(String.Format("{0,-10} | {1,-20} | {2,-10} | {3,-10}", tmp.Lexema, tmp.Token, tmp.PosMemoria, tmp.Tipo));
			}
            Console.WriteLine("Total: " + lista.Count);
		}


        internal TipoToken ObtemTipo(string aLexema)
        {
            string Chave = "";
            if (lista.ContainsKey(Convert.ToString(0) + aLexema))
            {
                Chave = Convert.ToString(0) + aLexema;
            }

            if (lista.ContainsKey(Convert.ToString(Escopo) + aLexema))
            {
                Chave = Convert.ToString(Escopo) + aLexema;
            }
            if (!Chave.Equals(""))
            {
                ItemSimboloTS s = (ItemSimboloTS)lista[Chave];
                return s.Tipo;
            }
            return TipoToken.t_nenhum;
        }
    }
}
